package com.ld.shieldsb.sensitiveword.service;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.ImmutableSet;
import com.ld.shieldsb.common.core.collections.ListUtils;
import com.ld.shieldsb.common.core.io.IOUtils;
import com.ld.shieldsb.common.core.model.PageBean;
import com.ld.shieldsb.common.core.model.Result;
import com.ld.shieldsb.common.core.util.PathUtil;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.core.util.properties.PropertiesPojo;
import com.ld.shieldsb.common.core.util.properties.PropertiesUtil;
import com.ld.shieldsb.common.core.util.sensitiveWord.SensitiveWordResult;
import com.ld.shieldsb.sensitiveword.Dictionary;
import com.ld.shieldsb.sensitiveword.DictionaryItem;
import com.ld.shieldsb.sensitiveword.handler.SensitiveWordHandler;
import com.ld.shieldsb.sensitiveword.handler.SensitiveWordHandlerFactory;

import lombok.Data;

/**
 * 敏感词处理器工具
 * 
 * @author <a href="mailto:donggongai@126.com" target="_blank">吕凯</a>
 * @date 2019年10月28日 上午8:41:08
 *
 */
@Data
public abstract class SensitiveWordService {

    public static final String CONFIG_DEFAULT_FILE_NAME = "sb-sensitiveword-default.properties"; // 默认配置文件名
    public static final String CONFIG_FILE_NAME = "sb-sensitiveword.properties"; // 项目配置文件名

    public static final PropertiesUtil CONFIG_DEFAULT = new PropertiesUtil(CONFIG_DEFAULT_FILE_NAME); // 默认配置
    public static PropertiesUtil CONFIG = new PropertiesUtil(CONFIG_FILE_NAME); // 项目配置，可覆盖默认配置
//  public static final PropertiesUtil CONFIG = new PropertiesUtil("D:\\Desktop\\sb-sensitiveword.properties"); // 项目配置，可覆盖默认配置

    public SensitiveWordHandler handler = loadHandler(); // 敏感词处理器

    protected Set<String> sensitiveWordSet = new LinkedHashSet<>(); // 敏感词
    protected Map<String, String> replaceWordMap = new LinkedHashMap<>(); // 替换词
    protected Map<String, String> wordDictionaryMap = new LinkedHashMap<>(); // 关键词和生效的字典的对应关系

    protected Set<String> dictionarysAllEmbed = ImmutableSet.of("xinhua", "web"); // 所有内置的库，不一定全部加载了，注意顺序是固定的

    protected Map<String, Dictionary> dictionarys = new LinkedHashMap<>(); // 加载的字典库，key为字典库文件名

    public static final int INT_NULL = -999; // int类型的默认空值

    public static final String CONFIG_SERVICE_TYPE = "sensitiveword.type"; // 字典库类型
    public static final String CONFIG_SERVICE_DICT_EMBED = "sensitiveword.dict"; // 内置字典库
    public static final String CONFIG_SERVICE_DICT_EXT = "sensitiveword.ext_dict"; // 扩展字典库
    public static final String CONFIG_HANDLER = "sensitiveword.handler"; // 敏感词处理器算法，内置DFA算法的实现，其他算法可自己实现

    public SensitiveWordHandler loadHandler() {
        String handlerKey = getString(CONFIG_HANDLER, null); // 先找项目中的配置文件，如果项目中无此配置则找默认配置文件
        handler = SensitiveWordHandlerFactory.getInstance().getService(handlerKey); // 敏感词处理器
        return handler;
    }

    /**
     * 加载全部字典库
     * 
     * @Title loadDict
     * @author 吕凯
     * @date 2019年10月28日 上午9:16:25 void
     */
    public abstract void loadDict();

    /**
     * 加载指定的库
     * 
     * @Title loadDict
     * @author 吕凯
     * @date 2019年11月4日 上午11:06:37
     * @param dicts
     *            void
     */
    public abstract void loadDict(List<String> dicts);

    public abstract String getDictName(String dictName);

    /**
     * 更新字典库
     * 
     * @Title updateDict
     * @author 吕凯
     * @date 2019年10月28日 下午5:10:01
     * @param file
     *            void
     */
    public abstract void updateDict(File file);

    /**
     * 将词典加载进处理器中
     * 
     * @Title loadDictionary
     * @author 吕凯
     * @date 2019年10月28日 上午11:24:04
     * @param dict
     *            void
     */
    public abstract void loadDictionary(Dictionary dict);

    public abstract void removeDictionary(Dictionary dict);

    /**
     * 
     * 根据文件名称获取字典库对象
     * 
     * @Title getDictionary
     * @author 吕凯
     * @date 2019年10月28日 上午10:42:08
     * @param dictName
     *            相对class的路径
     * @return Dictionary
     */
    public abstract Dictionary getDictionary(String dictName);

    /**
     * 根据file对象获取字典库
     * 
     * @Title getDictionary
     * @author 吕凯
     * @date 2019年10月28日 下午4:45:17
     * @param dictFile
     * @return Dictionary
     */
    public abstract Dictionary getDictionary(File dictFile);

    /**
     * 检查敏感词
     * 
     * @Title check
     * @author 吕凯
     * @date 2019年10月30日 下午5:25:25
     * @param text
     * @return SensitiveWordResult
     */
    public SensitiveWordResult check(String text) {
        return handler.check(text);
    }

    public static String getServiceType() {
        return getString(CONFIG_SERVICE_TYPE, SensitiveWordServiceType.FILE.getValue());
    }

    public static String getString(String paramName, String defaultV) {
        String value = CONFIG.getString(paramName, null); // 先找项目中的配置文件，如果项目中无此配置则找默认配置文件
        if (value == null) {
            value = CONFIG_DEFAULT.getString(paramName, defaultV);
        }
        return value;
    }

    public static int getInt(String paramName, int defaultV) {
        int value = CONFIG.getInt(paramName, INT_NULL); // 先找项目中的配置文件，如果项目中无此配置则找默认配置文件
        // 如果没有取到值，则再去默认配置
        if (value == INT_NULL) {
            value = CONFIG_DEFAULT.getInt(paramName, defaultV);
        }
        return value;
    }

    /**
     * 重载配置文件
     * 
     * @Title reloadConfig
     * @author 吕凯
     * @date 2019年10月30日 下午6:01:31 void
     */
    public void reloadConfig() {
        CONFIG = new PropertiesUtil(CONFIG_FILE_NAME);
    }

    // 获取所有内置库
    public abstract List<Dictionary> getDictsEmbedAll();

    // 获取加载的内置库
    public abstract List<Dictionary> getDictsEmbedLoad();

    // 获取加载的内置库
    public abstract List<Dictionary> getDictsExtAll();

    // 获取所有扩展库
    public abstract List<Dictionary> getDictsExtLoad();

    // 删除字典条目
    public abstract Result delDictItem(String dictFileName, String word, Map<String, Object> extendModel);

    public abstract Result addDictItem(String dictFileName, DictionaryItem item, Map<String, Object> extendModel);

    /**
     * 分页搜索
     * 
     * @Title getDictionaryItemPageBean
     * @author 吕凯
     * @date 2019年10月31日 上午11:18:09
     * @param queryModel
     *            使用DictionaryItem封装的查询
     * @param extendQueryModel
     *            扩展查询对象，如果前面的搜索条件不满足可以自己放到Map中扩展
     * @param pageNum
     * @param pageSize
     * @return PageBean<DictionaryItem>
     */
    public abstract PageBean<DictionaryItem> getDictionaryItemPageBean(DictionaryItem queryModel, Map<String, Object> extendQueryModel,
            int pageNum, int pageSize);

    /**
     * 获取配置信息
     * 
     * @Title getSetInfo
     * @author 吕凯
     * @date 2019年10月31日 上午9:32:45
     * @return List<PropertiesPojo>
     */
    public List<PropertiesPojo> getSetInfo() {
        List<PropertiesPojo> configProjectList = CONFIG.getPropertys();
        List<PropertiesPojo> configDefaultList = CONFIG_DEFAULT.getPropertys();
        final List<PropertiesPojo> configList = new ArrayList<>(); // 赋值到新List中
        if (ListUtils.isNotEmpty(configDefaultList)) { // 读取默认配置，如果项目中的配置存在相同的key，则使用项目中的覆盖默认的
            if (ListUtils.isNotEmpty(configProjectList)) { // 项目配置存在则循环处理
                configDefaultList.stream().forEach(config -> {
                    int index = configProjectList.indexOf(config); // 项目配置中存在
                    if (index >= 0) {
                        PropertiesPojo propconfig = configProjectList.get(index);
                        config.setValue(propconfig.getValue());
                        if (StringUtils.isNotEmpty(propconfig.getComment())) { // 注释不为空则覆盖，为空仍使用原来的
                            config.setComment(propconfig.getComment());
                        }
                    }
                    configList.add(config);
                });
            } else { // 项目配置不存在直接取默认配置
                configList.addAll(configDefaultList);
            }
        }
        return configList;
    }

    public Result createConfigFile() {
        Result result = new Result();
        String classRootPath = PathUtil.getClassRootPath(true);
        if (!StringUtils.isEmpty(classRootPath)) {
            File configFile = new File(classRootPath, SensitiveWordService.CONFIG_FILE_NAME); // 判断文件是否存在
            if (!configFile.exists()) {
                IOUtils.readResource2File("/" + SensitiveWordService.CONFIG_FILE_NAME, configFile);
                result.setSuccess(true);
            } else {
                result.setMessage("配置文件已存在！");
                return result;
            }
        }
        reloadConfig();
//        System.out.println("getURL==" + SensitiveWordHandlerUtil.CONFIG.getURL());
        result.setSuccess(true);
        result.setMessage("创建配置文件成功！");
        return result;
    }

}
